package com.cskaoyan.javase.thread._5pc._1wait_notify;

import com.sun.corba.se.impl.ior.ObjectKeyFactoryImpl;

/**
 * 利用线程的唤醒等待机制，实现以下需求：
 * 创建2个线程，A线程和B线程。
 * A线程打印1，B线程打印2，A线程打印3，B线程打印4....
 * A和B两个线程轮流打印数字，直到打印到100为止。
 * A打印1-100的奇数,B打印1-100的偶数
 * 轮流打印,一个接一个
 *
 * 思路:
 *      1.A线程先执行,先让A线程唤醒notify B线程,让B打印2(但是此时锁没有释放,A继续执行,B没有锁无法执行)
 *          然后A打印1,不能让它继续打印2,要自己阻塞自己wait,释放锁
 *      2.B线程后执行,先让B线程唤醒notify A线程,让A打印3(但是此时锁没有释放,B继续执行,A没有锁无法执行)
 *            然后B打印2,不能让它继续打印3,要自己阻塞自己wait,释放锁
 *
 *
 * 代码写完后,为什么程序没有结束呢?
 * 程序之所以没有结束,说明有线程阻塞,也就是有线程wait,需要等待唤醒
 *
 * @since 11:13
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Exercise {
    private static final Object OBJECT = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (OBJECT) {
                for (int i = 1; i <= 100; i += 2) {
                    // 唤醒B线程
                    OBJECT.notify();
                    System.out.println(Thread.currentThread().getName() + "打印了:" + i);
                    // 阻塞自己,wait,释放锁对象
                    try {
                        OBJECT.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // A执行完毕后,唤醒B线程
                OBJECT.notify();
            }
        }, "A").start();

        // 主线程休眠1s,保证A先执行
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            synchronized (OBJECT) {
                for (int i = 2; i <= 100; i += 2) {
                    // 唤醒A线程
                    OBJECT.notify();
                    System.out.println(Thread.currentThread().getName() + "打印了:" + i);
                    // 阻塞自己,wait,释放锁对象
                    try {
                        OBJECT.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // B执行完毕后,唤醒A线程
                OBJECT.notify();
            }
        }, "B").start();
    }
}
